// bluetooth.c
// 蓝牙设备
#include "freertos/FreeRTOS.h"  // xTaskCreate
#include "esp_log.h"  // ESP_LOGI
#include "esp_bt.h"  // esp_bt_controller_enable
#include "esp_bt_main.h"  // esp_bluedroid_init
#include "esp_gap_ble_api.h"  // esp_ble_gap_register_callback
#include "esp_hidh.h"  // esp_ble_gattc_register_callback
#include "esp_hidd.h"  // esp_hidd_dev_input_set
#include "freertos/queue.h"  // xQueueCreate
#include "common.h"

// 内部变量
static const char *TAG = "BLUETOOTH";
static SemaphoreHandle_t syncSemaphore = NULL;  // 进程同步
struct scan_result_t {  // 扫描结果
  struct scan_result_t *next;  // 下一个
  esp_bd_addr_t bda;  // 地址
  esp_ble_addr_type_t addr_type;  // 地址类型
};
static struct scan_result_t *scan_results = NULL;  // 扫描结果
static esp_hidd_dev_t *hid_dev = NULL;  // 设备

struct message_t {  // 输入的数据
    uint8_t data[16];  // 键盘数据
    uint16_t len;  // 数据长度
};
QueueHandle_t messageQueue = NULL;  // 消息队列

const unsigned char mouseReportMap[] = {
  //--------键盘--------//
  0x05, 0x01,        // Usage Page (Generic Desktop Ctrls)
  0x09, 0x06,        // Usage (Keyboard)
  0xA1, 0x01,        // Collection (Application)
  0x85, 0x01,        //   Report ID (1)
  0x05, 0x07,        //   Usage Page (Kbrd/Keypad)
  0x19, 0xE0,        //   Usage Minimum (0xE0)
  0x29, 0xE7,        //   Usage Maximum (0xE7)
  0x15, 0x00,        //   Logical Minimum (0)
  0x25, 0x01,        //   Logical Maximum (1)
  0x75, 0x01,        //   Report Size (1)
  0x95, 0x08,        //   Report Count (8)
  0x81, 0x02,        //   Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
  0x95, 0x01,        //   Report Count (1)
  0x75, 0x08,        //   Report Size (8)
  0x81, 0x03,        //   Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
  0x95, 0x05,        //   Report Count (5)
  0x75, 0x01,        //   Report Size (1)
  0x05, 0x08,        //   Usage Page (LEDs)
  0x19, 0x01,        //   Usage Minimum (Num Lock)
  0x29, 0x05,        //   Usage Maximum (Kana)
  0x91, 0x02,        //   Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
  0x95, 0x01,        //   Report Count (1)
  0x75, 0x03,        //   Report Size (3)
  0x91, 0x03,        //   Output (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
  0x95, 0x05,        //   Report Count (5)
  0x75, 0x08,        //   Report Size (8)
  0x15, 0x00,        //   Logical Minimum (0)
  0x25, 0x65,        //   Logical Maximum (101)
  0x05, 0x07,        //   Usage Page (Kbrd/Keypad)
  0x19, 0x00,        //   Usage Minimum (0x00)
  0x29, 0x65,        //   Usage Maximum (0x65)
  0x81, 0x00,        //   Input (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
  0xC0,              // End Collection
  //--------鼠标--------//
  0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
  0x09, 0x02,                    // USAGE (Mouse)
  0xa1, 0x01,                    // COLLECTION (Application)
  0x85, 0x02,                    //   Report ID (2)
  0x09, 0x01,                    //   USAGE (Pointer)
  0xa1, 0x00,                    //   COLLECTION (Physical)
  0x05, 0x09,                    //     USAGE_PAGE (Button)
  0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
  0x29, 0x03,                    //     USAGE_MAXIMUM (Button 3)
  0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
  0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
  0x95, 0x03,                    //     REPORT_COUNT (3)
  0x75, 0x01,                    //     REPORT_SIZE (1)
  0x81, 0x02,                    //     INPUT (Data,Var,Abs)
  0x95, 0x01,                    //     REPORT_COUNT (1)
  0x75, 0x05,                    //     REPORT_SIZE (5)
  0x81, 0x03,                    //     INPUT (Cnst,Var,Abs)
  0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
  0x09, 0x30,                    //     USAGE (X)
  0x09, 0x31,                    //     USAGE (Y)
  0x09, 0x38,                    //     USAGE (Wheel)
  0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
  0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
  0x75, 0x08,                    //     REPORT_SIZE (8)
  0x95, 0x03,                    //     REPORT_COUNT (3)
  0x81, 0x06,                    //     INPUT (Data,Var,Rel)
  0xc0,                          //   END_COLLECTION
  0xc0,                           // END_COLLECTION
};

static esp_hid_raw_report_map_t report_maps[] = {
  { .data = mouseReportMap, .len = sizeof(mouseReportMap) }
};

// HID主机回调函数
static void hidh_callback(void *args, esp_event_base_t base, int32_t id,
void *data) {
  esp_hidh_event_t event = (esp_hidh_event_t)id;
  esp_hidh_event_data_t *param = (esp_hidh_event_data_t*)data;
  switch (event) {
    case ESP_HIDH_INPUT_EVENT: {  // 输入事件
      if (param->input.length==8 || param->input.length==4) {
        struct message_t message;
        memcpy(message.data, param->input.data, param->input.length);
        message.len = param->input.length;
        xQueueSend(messageQueue, &message, 0);
      }
      break;
    }
    default: {
      ESP_LOGI(TAG, "EVENT: %d", event);
      break;
    }
  }
}

void keyboard_forward_task(void *arg) {
  struct message_t message;
  uint8_t data[16] = {0};
  while (true) {  // 阻塞等待队列消息
    if (xQueueReceive(messageQueue, &message, portMAX_DELAY)) {
      // ESP_LOG_BUFFER_HEX(TAG, message.data, message.len);
      memcpy(data, message.data, message.len);
      if (message.len == 8) {  // 键盘输入
        if ( (message.data[0]&0x01) > 0) {  // 重映射方向键盘
          data[0] -= 0x01;
          for (uint8_t i=1; i<8; i++) {
            if      (data[i] == 0x0b) { data[i] = 0x50; break; }  // h->左
            else if (data[i] == 0x0d) { data[i] = 0x51; break; }  // j->下
            else if (data[i] == 0x0e) { data[i] = 0x52; break; }  // k->上
            else if (data[i] == 0x0f) { data[i] = 0x4f; break; }  // l->右
          }
        }
        for (uint8_t i=1; i<8; i++) {  // capslock 改 ctrl
          if (message.data[i] == 0x39) {
            data[i] = 0x00;
            data[0] |= 0x01;
            break;
          }
        }
        esp_hidd_dev_input_set(hid_dev, 0, 1, data, 8);
      }
      if (message.len == 4) {  // 鼠标输入
        if (message.data[0] == 0x04) { data[0] = 0x00; }  // 屏蔽中键
        esp_hidd_dev_input_set(hid_dev, 0, 2, data, 4);
      }
    }
  }
}

// HID设备回调函数
static void hidd_callback(void *handler_args, esp_event_base_t base, int32_t id,
void *data) {
  esp_hidd_event_t event = (esp_hidd_event_t)id;
  switch (event) {
    case ESP_HIDD_CONNECT_EVENT: {
      xSemaphoreGive(syncSemaphore);
      break;
    }
    case ESP_HIDD_START_EVENT: {  // 开始
      esp_ble_adv_params_t hidd_adv_params = {
        .adv_int_min        = 0x20,
        .adv_int_max        = 0x30,
        .adv_type           = ADV_TYPE_IND,
        .own_addr_type      = BLE_ADDR_TYPE_PUBLIC,
        .channel_map        = ADV_CHNL_ALL,
        .adv_filter_policy  = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
      };
      esp_ble_gap_start_advertising(&hidd_adv_params);
      break;
    }
    default: {
      ESP_LOGI(TAG, "EVENT: %d", event);
      break;
    }
  }
}

// 通用访问回调，用于底层交互，如：扫描、配对
static void gap_handler(esp_gap_ble_cb_event_t event,
esp_ble_gap_cb_param_t *arg) {
  switch (event) {
    case ESP_GAP_BLE_SCAN_RESULT_EVT: {  // 有扫描结果
      if (arg->scan_rst.search_evt == ESP_GAP_SEARCH_INQ_RES_EVT) {  // 有设备
        uint16_t uuid = 0;
        uint8_t uuid_len = 0;
        char name[64] = {0};
        uint8_t name_len = 0;
        uint8_t *uuid_d = esp_ble_resolve_adv_data_by_type(
          arg->scan_rst.ble_adv,
          arg->scan_rst.adv_data_len+arg->scan_rst.scan_rsp_len,
          ESP_BLE_AD_TYPE_16SRV_CMPL,
          &uuid_len
        );
        if (uuid_d != NULL && uuid_len) {
            uuid = uuid_d[0] + (uuid_d[1] << 8);
        }
        if (uuid != ESP_GATT_UUID_HID_SVC) { break; }  // 跳过不可连接的设备
        ESP_LOGI(TAG, ESP_BD_ADDR_STR, ESP_BD_ADDR_HEX(arg->scan_rst.bda));
        uint8_t *adv_name = esp_ble_resolve_adv_data_by_type(
          arg->scan_rst.ble_adv,
          arg->scan_rst.adv_data_len+arg->scan_rst.scan_rsp_len,
          ESP_BLE_AD_TYPE_NAME_CMPL,
          &name_len
        );
        if (adv_name != NULL && name_len) {  // 有名字
          memcpy(name, adv_name, name_len);
          name[name_len] = '\0';
        } else {  // 没有名字
          adv_name = esp_ble_resolve_adv_data_by_type(
            arg->scan_rst.ble_adv,
            arg->scan_rst.adv_data_len+arg->scan_rst.scan_rsp_len,
            ESP_BLE_AD_TYPE_NAME_SHORT,
            &name_len
          );
        }
        if (name_len) {
          ESP_LOGI(TAG, "%s", name);
        }
        struct scan_result_t *r =  // 赋值结果
          (struct scan_result_t*)malloc(sizeof(struct scan_result_t));
        memcpy(r->bda, arg->scan_rst.bda, sizeof(esp_bd_addr_t));
        r->addr_type = arg->scan_rst.ble_addr_type;
        r->next = scan_results;
        scan_results = r;
      }
      if (arg->scan_rst.search_evt == ESP_GAP_SEARCH_INQ_CMPL_EVT) {  // 结束了
        xSemaphoreGive(syncSemaphore);
      }
      break;
    }
    case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: {  // 设置扫描参数
      xSemaphoreGive(syncSemaphore);
      break;
    }
    case ESP_GAP_BLE_NC_REQ_EVT: {  // 确认配对数
      esp_ble_confirm_reply(arg->ble_security.key_notif.bd_addr, true);
      break;
    }
    case ESP_GAP_BLE_SEC_REQ_EVT: {  // 可以加密
      esp_ble_gap_security_rsp(arg->ble_security.ble_req.bd_addr, true);
      break;
    }
    case ESP_GAP_BLE_PASSKEY_NOTIF_EVT: {  // 让键盘输入密码
      ESP_LOGI(TAG, "input:%" PRIu32, arg->ble_security.key_notif.passkey);
      break;
    }
    default: {  // 忽略其他
      ESP_LOGI(TAG, "gap event %d", event);
      break;
    }
  }
}

void bluetooth_init(void *arg) {
{ /*--------初始化--------*/
  syncSemaphore = xSemaphoreCreateBinary();  // 蓝牙扫描 互相通讯用
  // 创建消息队列
  messageQueue = xQueueCreate(128, sizeof(struct message_t));



  // 1. 初始化蓝牙控制器
  esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
  esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
  ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg));
  ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE));
  // 2. 初始化蓝牙协议栈
  ESP_ERROR_CHECK(esp_bluedroid_init());
  ESP_ERROR_CHECK(esp_bluedroid_enable());

  // 3. 删除历史配对
  int num = esp_ble_get_bond_device_num();
  esp_ble_bond_dev_t dev_list[num];
  esp_ble_get_bond_device_list(&num, dev_list);
  for (int i=0; i<num; i++) {
    esp_ble_remove_bond_device(dev_list[i].bd_addr);
  }
  // 4. 注册GAP
  ESP_ERROR_CHECK(esp_ble_gap_register_callback(gap_handler));
  ESP_ERROR_CHECK(esp_ble_gattc_register_callback(esp_hidh_gattc_event_handler));
  ESP_ERROR_CHECK(esp_ble_gatts_register_callback(esp_hidd_gatts_event_handler));
  // 5. 设定host的GAP参数
  esp_ble_scan_params_t scan_params = {
    .scan_type = BLE_SCAN_TYPE_ACTIVE,  // 主动扫描
    .own_addr_type = BLE_ADDR_TYPE_PUBLIC,  // 公共地址
    .scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,  // 允许所有设备
    .scan_interval = 0x50,  // 50ms扫描一次
    .scan_window = 0x30,  // 扫描持续30ms
    .scan_duplicate = BLE_SCAN_DUPLICATE_ENABLE,  // 允许重复应答
  };
  esp_ble_gap_set_scan_params(&scan_params);
  xSemaphoreTake(syncSemaphore, portMAX_DELAY);
  // 6. 初始化HID主机
esp_ble_gap_set_security_param(ESP_BLE_SM_IOCAP_MODE,
    &(esp_ble_io_cap_t){ESP_IO_CAP_IO}, 1);
esp_ble_gap_set_security_param(ESP_BLE_SM_AUTHEN_REQ_MODE, 
    &(esp_ble_auth_req_t){ESP_LE_AUTH_REQ_SC_MITM_BOND}, 1);
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_INIT_KEY, 
    &(uint8_t){ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK}, 1);
esp_ble_gap_set_security_param(ESP_BLE_SM_SET_RSP_KEY, 
    &(uint8_t){ESP_BLE_ENC_KEY_MASK | ESP_BLE_ID_KEY_MASK}, 1);
  esp_hidh_config_t host_config = {
    .callback = hidh_callback,  // 回调函数
    .event_stack_size = 4096,  // 回调函数栈大小
    .callback_arg = NULL,  // 回调函数参数
  };
  ESP_ERROR_CHECK(esp_hidh_init(&host_config));  // 初始化HID主机
}
  // 7. 设定device的GAP参数
  esp_ble_adv_data_t adv_data = {
    .set_scan_rsp = false,
    .include_name = true,
    .include_txpower = true,
    .min_interval = 0x0001,
    .max_interval = 0x0006,
    .appearance = ESP_HID_APPEARANCE_KEYBOARD,
    .manufacturer_len = 0,
    .p_manufacturer_data =  NULL,
    .service_data_len = 0,
    .p_service_data = NULL,
    .service_uuid_len = 16*sizeof(uint8_t),
    .p_service_uuid = (uint8_t[]){0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00,
      0x80, 0x00, 0x10, 0x00, 0x00, 0x12, 0x18, 0x00, 0x00},
    .flag = 0x6,
  };
  esp_ble_gap_set_device_name("BlueRemap");
  esp_ble_gap_config_adv_data(&adv_data);
  // 8. 初始化HID设备
  esp_hid_device_config_t device_config = {
    .vendor_id          = 0x16C0,
    .product_id         = 0x05DF,
    .version            = 0x0100,
    .device_name        = "BlueRemap",
    .manufacturer_name  = "Espressif",
    .serial_number      = "1234567890",
    .report_maps        = report_maps,
    .report_maps_len    = 1
  };
  ESP_ERROR_CHECK(esp_hidd_dev_init(&device_config, ESP_HID_TRANSPORT_BLE,
    hidd_callback, &hid_dev));
  xSemaphoreTake(syncSemaphore, portMAX_DELAY);

printf("蓝牙初始化完成\n");
printf("开始等待设备\n");
  vTaskDelay(10*1000 / portTICK_PERIOD_MS);
printf("开始扫描设备\n");

  esp_ble_gap_start_scanning(1);  // 扫描设备
  xSemaphoreTake(syncSemaphore, portMAX_DELAY);
  if (scan_results != NULL) {  // 找到设备就连接第一个
    esp_hidh_dev_open(scan_results->bda, ESP_HID_TRANSPORT_BLE, scan_results->addr_type);
  }
  while (scan_results != NULL) {  // 释放扫描空间
    struct scan_result_t *r = scan_results;
    scan_results = scan_results->next;
    free(r);
  }
  printf("scan done\n");
  xTaskCreate(keyboard_forward_task, "keyboard_forward", 2048, NULL, 5, NULL);
  // while(true) {
  //   static uint8_t myData1[4] = {0x00, 0x00, 0xF0, 0x00};
  //   ESP_ERROR_CHECK(esp_hidd_dev_input_set(hid_dev, 0, 2, myData1, 4)); 
  //   uint8_t myData2[8] = {0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00};
  //   ESP_ERROR_CHECK(esp_hidd_dev_input_set(hid_dev, 0, 1, myData2, 8));
  //   vTaskDelay(100 / portTICK_PERIOD_MS);
  //   uint8_t myData3[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
  //   ESP_ERROR_CHECK(esp_hidd_dev_input_set(hid_dev, 0, 1, myData3, 8));
  //   vTaskDelay(3*1000 / portTICK_PERIOD_MS);
  //   printf("按键+移动\n");
  // }
}
